import { Field, widgets as ws } from '../form/form';
import { cells as cs } from '../table/table';
import { Er, Erx } from '../elementUI';
import { buttons as bs } from '../button/button';
import { pascals as ps } from '../model/pascal';
import { WidgetName } from '../form/widgets';
import { CellName } from '../table/cells';
import { ButtonName } from '../button/buttons';
import { PascalName } from '../model/pascal';
import { MakerNames } from './layouts';
import { InjectionKey, Ref } from 'vue';
import { View } from '../core';
import { PageName } from '../../pages/pages';

/**
 * # 系列
 */
export declare interface Series extends Er {
  /**
   * 内置的集合列表
   */
  collections: Collection[];
  /**
   * 自身结构
   */
  fields?: Field[];
  /**
   * 自身默认值
   */
  default?: Record<string, unknown>;
}

/**
 * ## 系列的集合
 */
export declare interface Collection<T extends string | number = string> extends Er {
  /**
   * 元件列表
   */
  items: Item<T>;
  /**
   * 元素结构列表
   */
  structures: Record<T, Field[]>;
  /**
   * 由于拖拽以后，index(name)丢失，需要一个指示
   * 通过 元件的 $key 从 structures 查找元素的结构定义
   */
  point: string;
  /**
   * 元件 -> 元素
   */
  convertor?: Convertor;
  /**
   * 元素的默认构件
   */
  before?: Field[];
  /**
   * 元素的默认构件
   */
  after?: Field[];
  /**
   * 布局
   */
  layout: Layout<T>;
  /**
   * 自动 name - label 字段
   */
  modeled?: boolean;
}
/**
 * ## 集合的布局
 */
export type Layout<T extends string | number = string> = {
  name: MakerNames;
  definition?: {
    type?: {
      key?: string;
      values?: Record<T, unknown>;
    };
    [p: string]: unknown;
  };
};
/**
 * ### 集合的元件
 */
export type Item<T extends string | number = string> = Record<T, Er>;
/**
 * ### 从元件到元素的转换
 *  extend: 直接提供给 to
 *  fromOrExclude: 1. false: exclude; 2. string: Kay-a -> lay-b
 */
export type Convertor = {
  extend?: Record<string, unknown>;
  fromOrExclude?: Record<string, string | false>;
};

/**
 * 转换
 */
export const convertor: (c: Convertor, el: Erx) => Erx = (c, el) => {
  const to: Erx = {
    name: el.name,
    ...(c.extend || {})
  };

  for (const key in el) {
    const v: string | false | undefined = c.fromOrExclude?.[key];

    if (v === false) continue;

    to[v ?? key] = el[key];
  }

  return to;
};

/**
 * ## 常见构件
 */
export const commons = {
  name: {
    name: 'name',
    label: '标识符',
    widget: 'input',
    required: true,
    default: ''
  } as Field,
  label: {
    name: 'label',
    label: '名称',
    widget: 'input',
    required: true,
    default: ''
  } as Field,
  rules: {
    name: 'rules',
    label: '校验',
    widget: 'checkbox',
    options: [
      {
        label: '邮件',
        value: 'email'
      },
      {
        label: '手机号',
        value: 'phone'
      },
      {
        label: '身份证',
        value: 'ID'
      }
    ]
  } as Field,
  length: {
    name: 'length',
    label: '文本长度',
    widget: 'number'
  } as Field,
  options: {
    name: 'options',
    label: '选项',
    widget: 'option'
  } as Field,
  placeholder: {
    name: 'placeholder',
    label: '占位文字',
    widget: 'input'
  } as Field,
  col: {
    name: 'col',
    label: '表单域排版',
    widget: 'number',
    max: 24,
    min: 1,
    step: 1,
    showStops: true,
    default: 24
  } as Field,
  align: {
    name: 'align',
    widget: 'radio',
    options: [
      {
        label: '左',
        value: 'left'
      },
      {
        label: '右',
        value: 'right'
      },
      {
        label: '中',
        value: 'center'
      }
    ],
    label: '对齐'
  } as Field,
  multiple: {
    label: '开启多选',
    name: 'multiple',
    widget: 'switch'
  } as Field,
  face: {
    name: 'face',
    label: '外观颜色',
    widget: 'radio',
    options: [
      {
        label: '默认',
        value: ''
      },
      {
        label: '成功绿',
        value: 'success'
      },
      {
        label: '警告黄',
        value: 'warning'
      },
      {
        label: '醒目红',
        value: 'danger'
      },
      {
        label: '平淡',
        value: 'info'
      }
    ]
  } as Field,
  size: {
    name: 'size',
    label: '外观大小',
    widget: 'radio',
    options: [
      {
        label: '默认',
        value: 'default'
      },
      {
        label: '大型',
        value: 'large'
      },
      {
        label: '小型',
        value: 'small'
      }
    ]
  } as Field,
  url: {
    name: 'url',
    label: '地址',
    widget: 'input',
    default: ''
  } as Field,
  icon: {
    name: 'icon',
    label: '图标',
    widget: 'input'
  } as Field,
  when: {
    widget: 'when',
    name: 'when',
    label: '条件'
  } as Field,
  style: {
    widget: 'text',
    name: 'style',
    label: '样式'
  } as Field,
  sensor: {
    widget: 'input',
    name: 'sensor',
    label: '关联字段'
  } as Field
};

/**
 * ## 表单表单域元件结构信息
 */
const widgets: Record<WidgetName, Field[]> = {
  input: [commons.placeholder, commons.rules],
  text: [
    {
      label: '高度',
      name: 'rows',
      widget: 'number',
      min: 1,
      max: 10,
      step: 1,
      showSteps: true
    }
  ],
  switch: [
    {
      name: 'active-icon-class',
      label: '打开状态图标的类名',
      widget: 'input',
      default: null
    },
    {
      name: 'inactive-icon-class',
      label: '关闭状态图标的类名',
      widget: 'input',
      default: null
    },
    {
      name: 'active-text',
      label: '打开状态文字描述',
      widget: 'input',
      default: null
    },
    {
      name: 'inactive-text',
      label: '关闭状态文字描述',
      widget: 'input',
      default: null
    }
  ],
  number: [
    {
      name: 'min',
      label: '最小值',
      default: 0,
      widget: 'number'
      // translate: (v: string | number) => parseInt(v)
    },
    {
      name: 'max',
      label: '最大值',
      widget: 'number',
      // translate: (v: string | number) => parseInt(v),
      default: 50
    },
    {
      name: 'step',
      label: '步长',
      widget: 'number',
      // translate: (v: string | number) => parseInt(v),
      default: 1
    },
    {
      name: 'showStops',
      label: '显示间断点',
      widget: 'switch',
      default: false
    },
    {
      name: 'range',
      label: '范围选择',
      widget: 'switch',
      default: false
    }
  ],
  relation: [],
  radio: [commons.options],
  checkbox: [commons.options],
  select: [
    commons.options,
    {
      name: 'multi',
      label: '多选',
      widget: 'switch',
      default: false
    },
    {
      name: 'filterable',
      label: '启用搜索',
      widget: 'switch',
      default: false
    },
    {
      name: 'remote',
      label: '远程搜索地址',
      widget: 'input',
      default: null,
      when: {
        filterable: true
      }
    }
  ],
  cascader: [commons.options],
  rate: [],
  color: [
    {
      name: 'show-alpha',
      label: '透明度',
      widget: 'switch',
      default: false
    }
  ],
  time: [],
  date: [
    {
      name: 'type',
      label: '类型',
      widget: 'radio',
      options: [
        {
          label: '年',
          value: 'year'
        },
        {
          label: '月',
          value: 'month'
        },
        {
          label: '日',
          value: 'date'
        },
        {
          label: '时',
          value: 'time'
        }
      ]
    }
  ],
  file: [
    {
      name: 'url',
      label: '上传地址',
      widget: 'input',
      required: true,
      default: null
    },
    {
      name: 'multiple',
      widget: 'switch',
      label: '多选',
      default: false
    },
    {
      name: 'limit',
      widget: 'number',
      when: {
        multiple: true
      },
      label: '个数限制',
      default: null
    },
    {
      name: 'complete-label',
      label: '完成文字',
      widget: 'input',
      required: true,
      default: null
    },
    {
      name: 'preload-label',
      label: '按钮标题',
      widget: 'input',
      required: true,
      default: null
    },
    {
      name: 'accept',
      widget: 'input',
      label: '类型限制',
      default: null
    }
  ],
  pair: []
};

/**
 * ## 表格单元格元件结构信息
 */
const cells: Record<CellName, Field[]> = {
  icon: [
    {
      label: '图标列表',
      name: 'icons',
      widget: 'input',
      default: null
    },
    {
      label: '标签列表',
      name: 'labels',
      widget: 'input',
      default: null
    },
    commons.sensor
  ],
  pic: [
    {
      label: '高度',
      name: 'height',
      widget: 'input'
    },
    {
      label: '宽度',
      name: 'width',
      widget: 'input'
    },
    {
      label: '适配',
      name: 'fit',
      widget: 'radio',
      options: [
        {
          label: '铺满',
          value: 'fill'
        },
        {
          label: '缩放',
          value: 'contain'
        },
        {
          label: '剪裁',
          value: 'cover'
        },
        {
          label: '原样',
          value: 'none'
        },
        {
          label: '最小',
          value: 'scale-down'
        }
      ]
    }
  ],
  url: [
    {
      label: 'url字段名',
      name: 'relation',
      widget: 'input',
      default: 'url'
    }
  ],
  tag: [
    {
      ...commons.face,
      name: 'face',
      label: '固定样式'
    },
    commons.sensor
  ],
  span: []
};

/**
 * 模型元素结构信息
 */
const pascals: Record<PascalName, Field[]> = {
  str: [
    commons.length,
    commons.rules,
    {
      label: '文本框类型',
      name: 'type',
      widget: 'radio',
      options: [
        {
          label: '文本',
          value: 'text'
        },
        {
          label: '密码',
          value: 'password'
        }
      ],
      default: 'text'
    },
    commons.placeholder
  ],
  bool: [],
  int: [
    {
      label: '字节长度',
      name: 'length',
      widget: 'number',
      min: 1,
      max: 8,
      showSteps: true
    }
  ],
  decimal: [
    {
      label: '启用双精度',
      name: 'double',
      widget: 'switch'
    }
  ],
  time: [],
  date: [
    {
      label: '启用时间戳',
      name: 'timestamp',
      widget: 'switch',
      default: true
    }
  ],
  select: [commons.multiple, commons.options],
  remote: [
    {
      label: '关联模型',
      name: 'remote',
      widget: 'relation'
    }
  ],
  ip: [],
  file: [
    {
      label: '上传地址',
      name: 'url',
      widget: 'input'
    }
  ],
  text: []
};

/**
 * ## 通用按钮
 */
export const button: Field[] = [commons.name, commons.label, commons.icon];
/**
 * ### 按钮结构定义
 */
const buttons: Record<ButtonName, Field[]> = {
  common: [...button],
  switch: [
    {
      ...commons.label,
      name: 'labels'
    },
    {
      ...commons.icon,
      name: 'icons'
    },
    {
      ...commons.face,
      name: 'faces'
    }
  ],
  dialog: [
    ...button,
    {
      ...commons.url,
      name: 'dialog'
    }
  ]
};

const collections = {
  fields: {
    name: 'fields',
    label: '表单域',
    point: 'widget',
    items: ws,
    structures: widgets,
    convertor: {
      extend: {
        col: 24
      },
      fromOrExclude: {
        icon: false,
        tag: false,
        name: 'widget',
        'on-create': false,
        onCreate: false
      }
    },
    before: [commons.label],
    after: [commons.when, commons.col],
    layout: {
      name: 'form'
    }
  } as Collection<WidgetName>,
  columns: {
    name: 'columns',
    label: '表单列',
    point: 'cell',
    items: cs,
    structures: cells,
    convertor: {
      fromOrExclude: {
        icon: false,
        name: 'cell'
      }
    },
    before: [commons.label],
    after: [
      commons.style,
      {
        ...commons.align,
        name: 'headerAlign',
        label: '表头对齐样式'
      },
      {
        ...commons.align,
        name: 'align',
        label: '对齐样式'
      },
      {
        name: 'sortable',
        label: '排序',
        widget: 'switch'
      },
      {
        name: 'fixed',
        label: '固定',
        widget: 'radio',
        options: [
          {
            label: '左侧',
            value: 'left'
          },
          {
            label: '右侧',
            value: 'right'
          },
          {
            label: '不固定',
            value: 'none'
          }
        ]
      },
      {
        name: 'resizable',
        label: '列宽可调节',
        widget: 'switch'
      }
    ],
    layout: {
      name: 'table',
      definition: {
        type: {
          key: 'cell',
          values: {
            icon: 'danger',
            pic: 'info',
            url: 'warning',
            tag: '',
            span: 'success'
          }
        }
      }
    }
  } as Collection<CellName>,
  buttons: {
    name: 'items',
    label: '按钮列表',
    point: 'species',
    items: bs,
    structures: buttons,
    convertor: {
      fromOrExclude: {
        icon: false,
        name: 'species'
      }
    },
    before: [
      {
        name: 'command',
        fields: [
          {
            name: 'request',
            label: '请求类型',
            widget: 'radio',
            options: [
              {
                label: 'get',
                value: 'get'
              },
              {
                label: 'post',
                value: 'post'
              }
            ]
          },
          commons.url,
          {
            name: 'payload',
            label: '负载',
            widget: 'input'
          },
          {
            name: 'directive',
            label: '内置指令',
            widget: 'input'
          },
          {
            name: 'layer',
            label: '响应的图层名',
            widget: 'input'
          }
        ]
      }
    ],
    after: [
      commons.face,
      commons.size,
      {
        name: 'round',
        label: '圆角',
        widget: 'switch',
        activeText: '圆角'
      },
      {
        name: 'circle',
        label: '圆形',
        widget: 'switch',
        activeText: '圆形'
      },
      {
        name: 'plain',
        label: '朴素按钮',
        widget: 'switch',
        activeText: '朴素按钮'
      },
      commons.when
    ],
    layout: {
      name: 'toolbar'
    }
  } as Collection<ButtonName>,
  elements: {
    name: 'elements',
    label: '元素列表',
    point: 'pascal',
    items: ps,
    structures: pascals,
    before: [commons.name, commons.label],
    convertor: {
      fromOrExclude: {
        name: 'pascal'
      }
    },
    layout: {
      name: 'tag',
      definition: {
        type: {
          key: 'pascal',
          values: {
            bool: 'success',
            int: 'success',
            select: 'danger',
            remote: 'success',
            str: '',
            text: 'info',
            date: 'warning',
            time: 'warning',
            decimal: 'info',
            ip: 'success',
            file: ''
          }
        }
      }
    }
  } as Collection<PascalName>
};

// export type CollectionName = keyof typeof collections;

/**
 * 表单
 */
export const form: Series = {
  name: 'form',
  label: '表单',
  fields: [
    commons.label,
    commons.name,
    commons.style,
    commons.size,
    {
      widget: 'input',
      name: 'labelWidth',
      label: '标签宽度'
    },
    {
      name: 'labelPosition',
      label: '标签位置',
      widget: 'radio',
      options: [
        {
          label: 'left',
          value: '左'
        },
        {
          label: 'right',
          value: '右'
        },
        {
          label: 'top',
          value: '换行'
        }
      ]
    }
  ],
  collections: [collections.fields]
};

/**
 * 表格
 */
export const table: Series = {
  name: 'table',
  label: '表格',
  collections: [collections.columns]
};

/**
 * 工具栏
 */
export const toolbar: Series = {
  name: 'toolbar',
  label: '工具栏',
  collections: [collections.buttons]
};

/**
 * ## 模型
 */
export const model: Series = {
  name: 'model',
  label: '模型设计',
  fields: [
    commons.name,
    commons.label,
    {
      label: '附加表',
      name: 'inner',
      widget: 'switch'
    }
  ],
  default: {
    name: 'model',
    label: '模型'
  },
  collections: [collections.elements]
};

export const cloner = (collection: Collection) => {
  const c = collection?.convertor;
  return (e: Erx): Erx => (c ? convertor(c, e) : { ...e });
};

/**
 * draggable-wrapper中默认插槽的参数
 */
export type MakerSlotParam = {
  selected: number;
  remove: (index?: number) => void;
  select: (index?: number) => void;
  update: (element?: Er, index?: number) => void;
};

/**
 * ## 从这里开始
 */

const series = {
  model,
  form,
  table,
  toolbar
};

export type SeriesName = keyof typeof series;

export const getSeries = (name: SeriesName) => series[name] || series.form;

// export interface Panel {
//   register: (closer: () => void) => () => void;
//   open: () => void;
//   close: () => void;
// }

export interface Element extends Er {
  pascal: PascalName;
}

export interface NamedView extends View {
  name: string;
}

export declare interface Model extends Er {
  elements?: Element[];
  inners?: string[];
  tree?: boolean;
  inner?: boolean;
}

export interface NamedModel extends Model {
  name: string;
}

export declare interface Controller extends Er {
  views: Record<string, NamedView>;
  model?: string;
}

export interface M2 extends Er {
  models: Record<string, NamedModel>;
  controllers: Record<string, Controller>;
}

export const m2InjectionKey: InjectionKey<() => M2> = Symbol('m2-instance');

export const FormFields: InjectionKey<Ref<Array<Field>>> = Symbol('form-fields');

export const Page2Series: (page?: PageName) => SeriesName | undefined = (vtype) => {
  if (!vtype) return undefined;
  if (vtype === 'Form') return 'form';
  if (vtype === 'Curd') return 'table';

  return undefined;
};

export const getCurdController: (name: string) => Controller = (model) => ({
  name: model,
  model,
  views: {
    add: {
      name: 'add',
      label: '新增',
      title: '新增',
      view: 'Form'
    },
    edit: {
      name: 'edit',
      title: '修改',
      label: '修改',
      view: 'Form'
    },
    curd: {
      name: 'curd',
      title: '列表',
      label: '列表',
      view: 'Curd'
    }
  }
});
